﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ChMetody_2
{
    class Kramer
    {
        /// <summary>
        /// Решение системы уравнение методом Крамера
        /// </summary>
        /// <param name="M">Матрица коеффициентов при неизвестных</param>
        /// <param name="L">Список свободных членов системы</param>
        /// <returns>Возвращает список корней системы уравнений</returns>
        public static List<double> solution(Matrix M, List<double> L)
        {
            double det = Kramer.Determinant(M);
            if (det == 0)
                MessageBox.Show("Система вырожденная!");
            List<double> temp = new List<double>(M.Rows.Count);
            for (int i = 0; i < M.Rows.Count; i++)
            {
                temp.Add(Determinant(changeCol(M, L, i)) / det);
            }
            return temp;
        }

        /// <summary>
        /// Заменить колонку в матрице
        /// </summary>
        /// <param name="M">Изходная матрица</param>
        /// <param name="l1">Список для замены колонки</param>
        /// <param name="index">Номер колонки для замены</param>
        /// <returns>Возвращает матрицу с замененной колонкой</returns>
        private static Matrix changeCol(Matrix M, List<double> l1, int index)
        {
            Matrix temp;
            M.CopyMatrix(out temp);
            for (int i = 0; i < temp.Rows.Count; i++)
                temp.Rows[i].Cells.RemoveAt(index);
            for (int i = 0; i < temp.Rows.Count; i++)
                temp.Rows[i].Cells.Insert(index, l1[i]);
            return temp;
        }

        /// <summary>
        /// Нахождение минора введённой матрицы M[row][col] // без изменений знака!!!
        /// </summary>
        /// <param name="M">Матрица для которой вычисляется минор</param>
        /// <param name="row">Вычеркиваемая строка</param>
        /// <param name="col">Вычеркиваемый столбец</param>
        /// <returns>Матрица которая является минором</returns>
        public static Matrix Minor(Matrix M, int row, int col)
        {
            Matrix temp; // Временная матрица
            M.CopyMatrix(out temp); // Просто копирование во временную матрицу temp для сохранения исходной M

            temp.Rows.RemoveAt(row);

            for (int i = 0; i < temp.Rows.Count; i++)
                temp.Rows[i].Cells.RemoveAt(col);

            return temp; // Возвращаем полученный минор
        }

        /// <summary>
        /// Рекурсивное вычисление детерминанта
        /// </summary>
        /// <param name="M">Ссылка на матрицу для которой вычисляется определитель</param>
        /// <returns>Число - определитель матрицы</returns>
        public static double Determinant(Matrix M)
        {
            // Проверки 
            if (M.Rows.Count == 0) return 0;
            if (M.Rows.Count != M.Rows[0].Cells.Count) return 0;

            if (M.Rows.Count == 1) return M.Rows[0].Cells[0];
            if (M.Rows.Count == 2) return M.Rows[0].Cells[0] * M.Rows[1].Cells[1] -
                                        M.Rows[0].Cells[1] * M.Rows[1].Cells[0];

            double det = 0;
            for (int j = 0; j < M.Rows[0].Cells.Count; j++)
                det += M.Rows[0].Cells[j] * Determinant(Minor(M, 0, j)) * Math.Pow(-1, j);
            Console.WriteLine("determin " + det);
            return det;
        }
    }
}
